package com.example.train_operate.ws.manager;

import com.example.train_operate.ws.model.UserSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 房间管理 管理房间和用户会话
 */
@Slf4j
@Component
public class RoomManager {

    /**
     * 房间最大人数
     */
    private static final Integer MAX_ROOM_SIZE = 4;

    /**
     * 房间映射: roomId -> Set<userId>
     */
    private final Map<String, Set<String>> rooms = new ConcurrentHashMap<>();

    /**
     * 用户会话映射: userId -> UserSession
     */
    private final Map<String, UserSession> sessions = new ConcurrentHashMap<>();

    /**
     * sessionId -> userId 映射
     */
    private final Map<String, String> sessionIdToUserId = new ConcurrentHashMap<>();

    /**
     * 用户加入房间
     */
    public synchronized boolean joinRoom(String roomId, UserSession userSession){
        String userId = userSession.getUserId();
        //检查用户是否已在其他房间
        if(sessions.containsKey(userId)) {
            String oldRoomId = sessions.get(userId).getRoomId();
            if(!oldRoomId.equals(roomId)){
                leaveRoom(userId);
            }
        }
        //检查房间是否已满
        Set<String> roomUsers = rooms.computeIfAbsent(roomId, k -> ConcurrentHashMap.newKeySet());
        if(roomUsers.size() >= MAX_ROOM_SIZE) {
            log.warn("房间人数已满，无法加入");
            return false;
        }
        //添加用户到房间
        roomUsers.add(userId);
        sessions.put(userId, userSession);
        sessionIdToUserId.put(userSession.getSession().getId(), userId);
        log.info("用户{}加入房间{}，当前房间人数为：{}", userId, roomId, roomUsers.size());
        return true;
    }

    /**
     * 用户离开房间
     */
    public synchronized void leaveRoom(String userId) {
        UserSession userSession = sessions.remove(userId);
        if (userSession == null){
            return;
        }
        String roomId = userSession.getRoomId();
        Set<String> roomUsers = rooms.get(roomId);
        if(roomUsers != null) {
            roomUsers.remove(userId);
            log.info("用户{}离开房间{}，当前房间人数为：{}", userId, roomId, roomUsers.size());
            //如果房间为空删除房间
            if(roomUsers.isEmpty()){
                rooms.remove(roomId);
                log.info("房间{}已删除", roomId);
            }
        }
        sessionIdToUserId.remove(userSession.getSession().getId());
    }

    /**
     * 通过 WebSocket sessionId 离开房间
     */
    public void leaveRoomBySessionId(String sessionId){
        String userId = sessionIdToUserId.get(sessionId);
        if(userId != null){
            leaveRoom(userId);
        }
    }

    /**
     * 获取房间内的所有用户Id
     */
    public List<String> getRoomUsers(String roomId){
        Set<String> roomUsers = rooms.get(roomId);
        if (roomUsers == null){
            return Collections.emptyList();
        }
        return new ArrayList<>(roomUsers);
    }

    /**
     * 获取房间内的所有用户会话
     */
    public List<UserSession> getRoomSessions(String roomId) {
        return getRoomUsers(roomId).stream()
                .map(sessions::get)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 获取用户会话
     */
    public UserSession getUserSession(String userId){
        return sessions.get(userId);
    }

    /**
     * 通过 sessionId 获取用户会话
     */
    public UserSession getUserSessionBySessionId(String sessionId) {
        String userId = sessionIdToUserId.get(sessionId);
        return userId != null ? sessions.get(userId) : null;
    }

    /**
     * 检查房间是否存在
     */
    public boolean roomExists(String roomId) {
        return rooms.containsKey(roomId);
    }

    /**
     * 获取房间人数
     */
    public int getRoomSize(String roomId) {
        Set<String> roomUsers = rooms.get(roomId);
        return roomUsers != null ? roomUsers.size() : 0;
    }

    /**
     * 清理过期会话（超过一小时未活动）
     */
    public void cleanupExpiredSessions(){
        long now = System.currentTimeMillis();
        long expirationTime = 60 * 60 * 1000; // 1小时

        List<String> expiredUsers = sessions.entrySet().stream()
                .filter(entry -> now - entry.getValue().getJoinTime() > expirationTime)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        expiredUsers.forEach(this::leaveRoom);
        if(!expiredUsers.isEmpty()){
            log.info("清理{}个过期会话", expiredUsers.size());
        }
    }
}
